package mystruct

import (
    "github.com/tealeg/xlsx"
    "github.com/xuri/excelize/v2"
    "github.com/klauspost/compress/zip"
    "encoding/csv"
	"os"
	"crypto/md5"
	"crypto/sha256"
	"io"
	"io/ioutil"
	"fmt"
	"path/filepath"
	"encoding/json"
	"strings"
	"sort"
	"time"
	"mime/multipart"
)

func Exists(path string) bool {  
    _, err := os.Stat(path)
    if err != nil {  
        if os.IsExist(err) {  
            return true  
        }  
        return false  
    }  
    return true  
}  

func IsDir(path string) bool {  
    s, err := os.Stat(path)  
    if err != nil {  
        return false  
    }  
    return s.IsDir()  
}  
  
 
func IsFile(path string) bool {  
    return !IsDir(path)  
}

func GetFileSize(filePath string) int64 {
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		return 0
	}
	return fileInfo.Size()
}

func GetMD5OfFile(filePath string) string {
	file, err := os.Open(filePath)
	if err != nil {
		return ""
	}
	defer file.Close()

	hasher := md5.New()
	_, err = io.Copy(hasher, file)
	if err != nil {
		return ""
	}

	return fmt.Sprintf("%x", hasher.Sum(nil))
}

func GetSHA256fFile(filePath string) string {
	file, err := os.Open(filePath)
	if err != nil {
		return ""
	}
	defer file.Close()

	hasher := sha256.New()
	_, err = io.Copy(hasher, file)
	if err != nil {
		return ""
	}

	return fmt.Sprintf("%x", hasher.Sum(nil))
}


func Dirmove(sourceDir, targetDir string) error {
	err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 计算目标路径
		targetPath := filepath.Join(targetDir, path[len(sourceDir):])

		// 如果是目录，则创建它
		if info.IsDir() {
			err = os.MkdirAll(targetPath, info.Mode())
			if err != nil {
				return err
			}
			return nil
		}

		// 如果是文件，则复制它
		srcFile, err := os.Open(path)
		if err != nil {
			return err
		}
		defer srcFile.Close()

		dstFile, err := os.Create(targetPath)
		if err != nil {
			return err
		}
		defer dstFile.Close()

		_, err = io.Copy(dstFile, srcFile)
		return err
	})

	if err == nil {
		os.RemoveAll(sourceDir)
	}
	return err
}

func ReadJSONFile(Jsonstruct *Mytoken) error {
	jsonFilePath := filepath.Join(Jsonstruct.Main_Path, "config.json")
	if !Exists(jsonFilePath) || !IsFile(jsonFilePath) {
	    Jsonstruct.Sleeptime = 1800
		Jsonstruct.Port = 8090
		keys, err := GenerateAESKey()
		if err != nil {
			return err
		}
		Jsonstruct.Key = keys
		err = WriteJSONFile(Jsonstruct)
		if err != nil {
			return fmt.Errorf("无法写入配置文件: %w", err)
		}
	}
	fileContent, err := ioutil.ReadFile(jsonFilePath)
	if err != nil {
		return fmt.Errorf("无法读取配置文件: %w", err)
	}
	var result Mytoken
	json.Unmarshal(fileContent, &result)
	Jsonstruct.Key = result.Key
	Jsonstruct.Port = result.Port
	Jsonstruct.Sleeptime = result.Sleeptime
	Jsonstruct.Download_Path = result.Download_Path
	Jsonstruct.Log_Path = result.Log_Path
	Jsonstruct.Initcode = result.Initcode
	return nil
}

func WriteJSONFile(Jsonstruct *Mytoken) error {
	jsonBytes, err := json.MarshalIndent(Jsonstruct, "", "  ")
	if err != nil {
		return err
	}
	jsonFilePath := filepath.Join(Jsonstruct.Main_Path, "config.json")

	err = ioutil.WriteFile(jsonFilePath, jsonBytes, 0644)
	if err != nil {
		return err
	}
	return nil
}

func IsFileLargerThan(path string, maxSize int64) bool {
    fileInfo, err := os.Stat(path)
    if err != nil {
        return false
    }
    return fileInfo.Size() > maxSize
}

func ListFilesInSegments(directory string, page int64, pageSize int64) ([]string, error) {
	files, err := ioutil.ReadDir(directory)
	if err != nil {
		return nil, err
	}

	sort.Slice(files, func(i, j int) bool {
    	return files[i].ModTime().After(files[j].ModTime())
	})

	startIndex := (page - 1) * pageSize
	endIndex := startIndex + pageSize
	if endIndex > int64(len(files)) {
		endIndex = int64(len(files))
	}

	var fileNames []string
	for _, file := range files[startIndex:endIndex] {
		fileNames = append(fileNames, file.Name())
	}

	return fileNames, nil
}

func GenerateCSV(data [][]string) string {
	var sb strings.Builder
	writer := csv.NewWriter(&sb)
	writer.WriteAll(data)
	writer.Flush()
	return sb.String()
}

func GenerateTXT(data [][]string) string {
	var sb strings.Builder
	for _, row := range data {
		sb.WriteString(strings.Join(row, ",")) // 使用制表符分隔
		sb.WriteString("\n")
	}
	return sb.String()
}

func GenerateXLS(data [][]string) string {
	file := excelize.NewFile()
	for rowIdx, rowData := range data {
		for colIdx, cellData := range rowData {
			cell, _ := excelize.CoordinatesToCellName(colIdx+1, rowIdx+1)
			file.SetCellValue("Sheet1", cell, cellData)
		}
	}
	var sb strings.Builder
	_, err := file.WriteTo(&sb)
	if err != nil {
		return ""
	}
	return sb.String()
}

// 读取 txt 文件
func ReadTxtFile(file multipart.File, key_list []ModelItems) ([]interface{}, error) {
	content, err := io.ReadAll(file)
	if err != nil {
		return nil, err
	}
	var make_map []interface{}
	lines := strings.Split(string(content), "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
        if line == "" {
            continue
        }
        columns := strings.Split(line, ",")
        map_app := make(map[string]interface{})
		for idx, item := range key_list {
            parsedValue, _ := parseValue(item.Select, safeGetColumnValue(columns, idx))
            map_app[item.Value] = parsedValue
		}
		make_map = append(make_map, Map_data{map_app, time.Now()})
	}
	return make_map, nil
}

// 读取 csv 文件
func ReadCsvFile(file multipart.File, key_list []ModelItems) ([]interface{}, error) {
	reader := csv.NewReader(file)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	var make_map []interface{}
	for _, record := range records {
		map_app := make(map[string]interface{})
        for idx, item := range key_list {
            parsedValue, _ := parseValue(item.Select, safeGetColumnValue(record, idx))
            map_app[item.Value] = parsedValue
        }
        make_map = append(make_map, Map_data{map_app, time.Now()})
	}
	return make_map, nil
}

// 读取 xls 文件
func ReadXlsFile(file multipart.File, key_list []ModelItems) ([]interface{}, error) {
	// 将文件保存到临时文件
	tempFile, err := os.CreateTemp("", "*.xls")
	if err != nil {
		return nil, err
	}
	defer os.Remove(tempFile.Name())

	if _, err := io.Copy(tempFile, file); err != nil {
        tempFile.Close()
        return nil, err
    }
    tempFile.Close() // 确保写入完成

	// 读取 xls 文件
	xlFile, err := xlsx.OpenFile(tempFile.Name())
	if err != nil {
		return nil, err
	}

	var make_map []interface{}
	if len(xlFile.Sheets) > 0 {
        sheet := xlFile.Sheets[0] // 第一个工作表
        for _, row := range sheet.Rows {
            map_app := make(map[string]interface{})
            for idx, item := range key_list {
                var cell *xlsx.Cell
                if idx < len(row.Cells) {
                    cell = row.Cells[idx]
                }
                strValue := ""
                if cell != nil {
                    strValue = cell.String()
                }
                parsedValue, _ := parseValue(item.Select, strValue)
                map_app[item.Value] = parsedValue
            }
            make_map = append(make_map, Map_data{map_app, time.Now()})
        }
    }
	return make_map, nil
}

func ZipDirectory(source, target string) error {
    // 创建ZIP文件
    zipFile, err := os.Create(target)
    if err != nil {
        return fmt.Errorf("创建ZIP文件失败: %w", err)
    }
    defer zipFile.Close()

    // 创建ZIP写入器
    zipWriter := zip.NewWriter(zipFile)
    defer zipWriter.Close()

    // 获取源目录的绝对路径
    absSource, err := filepath.Abs(source)
    if err != nil {
        return fmt.Errorf("获取绝对路径失败: %w", err)
    }

    // 遍历目录
    return filepath.Walk(absSource, func(filePath string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        // 创建文件头信息
        header, err := zip.FileInfoHeader(info)
        if err != nil {
            return fmt.Errorf("创建文件头失败: %w", err)
        }

        // 确保路径使用正斜杠(跨平台兼容)
        header.Name = filepath.ToSlash(filePath)

        // 转换为相对路径
        relPath, err := filepath.Rel(absSource, filePath)
        if err != nil {
            return fmt.Errorf("获取相对路径失败: %w", err)
        }
        header.Name = filepath.ToSlash(relPath)

        // 如果是目录，需要在名称后加/
        if info.IsDir() {
            header.Name += "/"
            _, err = zipWriter.CreateHeader(header)
            return err
        }

        // 设置压缩方法
        header.Method = zip.Deflate

        // 创建文件写入器
        writer, err := zipWriter.CreateHeader(header)
        if err != nil {
            return fmt.Errorf("创建ZIP条目失败: %w", err)
        }

        // 如果是普通文件，写入内容
        if !info.Mode().IsRegular() {
            return nil // 跳过非普通文件(如符号链接)
        }

        file, err := os.Open(filePath)
        if err != nil {
            return fmt.Errorf("打开文件失败: %w", err)
        }
        defer file.Close()

        _, err = io.Copy(writer, file)
        if err != nil {
            return fmt.Errorf("写入ZIP内容失败: %w", err)
        }

        return nil
    })
}